/*
** Principal data structures for the LEMON parser generator.
*/

#ifndef _STRUCT_H_
#define _STRUCT_H_

#include <cstring>
#include <vector>
#include <list>

/* Symbols (terminals and nonterminals) of the grammar are stored
** in the following: */
enum symbol_type {
  TERMINAL,
  NONTERMINAL,
  MULTITERMINAL
};
enum e_assoc {
    LEFT,
    RIGHT,
    NONE,
    UNK
};
class Rule;
class Symbol {
public:
  Symbol(const char*);
  const char *name;        /* Name of the symbol */
  int index;               /* Index number for this symbol */
  enum symbol_type type;   /* Symbols are all either TERMINALS or NTs */
  std::list<Rule*> rules;  /* Linked list of rules of this (if an NT) */
  Symbol *fallback; /* fallback token in case this token doesn't parse */
  int prec;                /* Precedence if defined (-1 otherwise) */
  enum e_assoc assoc;      /* Associativity if precedence is defined */
  char *firstset;          /* First-set for all rules of this symbol */
  bool lambda;             /* True if NT and can generate an empty string */
  int useCnt;              /* Number of times used */
  char *destructor;        /* Code which executes whenever this symbol is
                           ** popped from the stack during error processing */
  int destructor_emitted;  /* Is the destructor code emitted */
  int destLineno;          /* Line number for start of destructor */
  char *datatype;          /* The data type of information held by this
                           ** object. Only used if type==NONTERMINAL */
  int dtnum;               /* The data type number.  In the parser, the value
                           ** stack is a union.  The .yy%d element of this
                           ** union is the correct data type for this object */

  /* The following fields are used by MULTITERMINALs only */
  std::vector<Symbol*> subsyms;  /* Array of constituent symbols */
};

/* Each production rule in the grammar is stored in the following
** structure.  */
class Rule {
public:
  Rule():lhs(0),lhsalias(0),lhsStart(0),ruleline(0)
        ,line(0),code(0),codePrefix(0),codeSuffix(0)
        ,precsym(0),index(0),iRule(0),canReduce(0){}
  Symbol *lhs;      /* Left-hand side of the rule */
  const char *lhsalias;    /* Alias for the LHS (NULL if none) */
  int lhsStart;            /* True if left-hand side is the start symbol */
  int ruleline;            /* Line number for the rule */
  std::vector<Symbol*> rhs;     /* The RHS symbols */
  std::vector<const char*> rhsalias;   /* An alias for each RHS symbol (NULL if none) */
  int line;                /* Line number at which code begins */
  const char *code;        /* The code executed when this rule is reduced */
  const char *codePrefix;  /* Setup code before code[] above */
  const char *codeSuffix;  /* Breakdown code after code[] above */
  Symbol *precsym;  /* Precedence symbol for this rule */
  int index;               /* An index number for this rule */
  int iRule;               /* Rule number as used in the generated tables */
  bool canReduce;       /* True if this rule is ever reduced */
};

class Config;
using ConfigList = std::list<Config*>;

class Action;
class Config;
/* Each state of the generated parser's finite state machine
** is encoded as an instance of the following structure. */
class State {
public:
  State():statenum(0),nTknAct(0),nNtAct(0)
         ,iTknOfst(0),iNtOfst(0),iDfltReduce(0),pDfltReduce(0)
         ,autoReduce(0){}
  ConfigList basis_configs;       /* The basis configurations for this state */
  ConfigList configs;      /* All configurations in this set */
  int statenum;            /* Sequential number for this state */
  std::list<Action*> actions;       /* Array of actions for this state */
  int nTknAct, nNtAct;     /* Number of actions on terminals and nonterminals */
  int iTknOfst, iNtOfst;   /* yy_action[] offset for terminals and nonterms */
  int iDfltReduce;         /* Default action is to REDUCE by this rule */
  Rule *pDfltReduce;/* The default REDUCE rule. */
  int autoReduce;          /* True if this is an auto-reduce state */
};
#define NO_OFFSET (-2147483647)

#define MemoryCheck(X) if((X)==0){ \
  extern void memory_error(); \
  memory_error(); \
}

#endif //_STURCT_H_
